﻿using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Blm.VisionCloud.FrameWork.Cached;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Utility.Redis;

namespace VisionCloud.Domain.Repository.Implement.Sys
{
    public class SysRolePermissionRepository : BaseRepository<SysRolePermission>, ISysRolePermissionRepository
    {
        private readonly ICached cached;

        public SysRolePermissionRepository(ICached cached)
        {
            this.cached = cached;
        }

        public async Task<SysRolePermissionDto> FindSysRolePermissionById(SysRolePermissionDto sysRolePermissionDto)
        {
            return Db.SysRolePermissions.Where(p => p.RolePermissionId == sysRolePermissionDto.RolePermissionId)
                    .Select(w => new SysRolePermissionDto()
                    {
                        RolePermissionId = w.RolePermissionId,
                        MenuFuncId = w.MenuFuncId,
                        RoleId = w.RoleId
                    }).SingleOrDefault();
        }

        public async Task<ApiPageResult> GetPage(SysRolePermissionCondition condition)
        {
            var list = await Query()
                .WhereIf(condition.SysRolePermissionId != Guid.Empty, w => w.RolePermissionId == condition.SysRolePermissionId)
                .WhereIf(condition.RoleId != Guid.Empty, w => w.RoleId == condition.RoleId)
                .WhereIf(condition.MenuFuncId != Guid.Empty, w => w.MenuFuncId == condition.MenuFuncId)
                .Select(w => w.CopyTo<SysRolePermissionDto>())
                .DefaultOrderByDescending(condition, w => w.RoleId)
                .ToPageList(condition);

            var result = condition.CopyTo<ApiPageResult>();
            result.PageData = list;
            return result;
        }

        /// <summary>
        /// 获取角色的菜单数据
        /// </summary>
        /// <param name="roleList"></param>
        /// <returns></returns>
        public async Task<List<RoleMenuPermissionDto>> FindSysRolePermission(List<Guid> roleList, bool fromCache = true)
        {
            string keyStr = string.Join(",", roleList);
            string keyStrHash = "RolePermission_" + keyStr.GetMD5();
            if (!fromCache)
            {
                cached.Remove(keyStrHash);
            }
            var jsonObj = cached.Get<List<RoleMenuPermissionDto>>(keyStrHash);
            if (jsonObj != null)
            {
                return jsonObj;
            }
            else
            {
                #region 查询数据库配置的权限

                #region 权限对应的菜单

                //权限对应的菜单
                var list = await (from roles in Db.SysRoles
                                  join rolePers in Db.SysRolePermissions on roles.RoleId equals rolePers.RoleId
                                  join menuFuncs in Db.SysMenuFuncs on rolePers.MenuFuncId equals menuFuncs.MenuFuncId
                                  join menus in Db.SysMenus on menuFuncs.MenuId equals menus.MenuId
                                  join parentMenus in Db.SysMenus on menus.ParentId equals parentMenus.MenuId into t
                                  from parentMenus in t.DefaultIfEmpty()
                                  where roleList.Contains(roles.RoleId)
                                  where roles.IsDeleted == false && rolePers.IsDeleted == false && menuFuncs.IsDeleted == false && menus.IsDeleted == false
                                  && parentMenus.IsDeleted == false
                                  orderby roles.RoleId, menus.MenuId, menus.Level, menus.Sort
                                  select new RoleMenuPermissionDto
                                  {
                                      RoleId = roles.RoleId,
                                      RoleName = roles.Name,
                                      MenuId = menuFuncs.MenuId,
                                      MenuName = menus.Name,
                                      MenuIcon = menus.Icon,
                                      MenuUrl = menus.Url,
                                      MenuComponent = menus.Component,
                                      ParentMenuId = menus.ParentId.GetValueOrDefault(),
                                      ParentMenuName = parentMenus.Name,
                                      MenuLevel = menus.Level,
                                      MenuSort = menus.Sort,
                                      RolePermissionId = rolePers.RolePermissionId,
                                      MenuFuncId = rolePers.MenuFuncId,
                                      MenuFuncName = menuFuncs.Name,
                                      FuncType = menuFuncs.Apis,
                                      MenuFuncComponent = menuFuncs.Component,
                                      MenuFuncUrl = menuFuncs.Component
                                  }).ToListAsync().ConfigureAwait(false);

                #endregion 权限对应的菜单

                #region 配置状态为必须加载的菜单

                var mustMenuList = await (from menus in Db.SysMenus
                                          join menuFuncs in Db.SysMenuFuncs on menus.MenuId equals menuFuncs.MenuId into t1
                                          from menuFuncs in t1.DefaultIfEmpty()
                                          join parentMenus in Db.SysMenus on menus.ParentId equals parentMenus.MenuId into t
                                          from parentMenus in t.DefaultIfEmpty()
                                          where menus.IsDeleted == false && menuFuncs.IsDeleted == false && parentMenus.IsDeleted == false && menus.Status == SysMenu.EnumMenuStatus.必须显示
                                          select new RoleMenuPermissionDto
                                          {
                                              MenuId = menus.MenuId,
                                              MenuName = menus.Name,
                                              MenuIcon = menus.Icon,
                                              MenuUrl = menus.Url,
                                              MenuComponent = menus.Component,
                                              ParentMenuId = menus.ParentId.GetValueOrDefault(),
                                              ParentMenuName = parentMenus.Name,
                                              MenuLevel = menus.Level,
                                              MenuSort = menus.Sort,
                                          }).ToListAsync().ConfigureAwait(false);

                if (mustMenuList.Count > 0)
                {
                    var appRoleList = list.Select(p => new RoleAppDto { RoleId = p.RoleId, RoleName = p.RoleName }).Distinct().ToList();
                    foreach (var appRole in appRoleList)
                    {
                        foreach (var menu in mustMenuList)
                        {
                            menu.RoleId = appRole.RoleId;
                            menu.RoleName = appRole.RoleName;
                            if (list.Count(p => p.MenuId == menu.MenuId && p.RoleId == menu.RoleId) == 0)
                            {
                                list.Add(menu);
                            }
                        }
                    }
                }

                #endregion 配置状态为必须加载的菜单

                #region 查找出权限对应的菜单的所有上级菜单，他们也应该加载处理

                var menuList = await (from n in Db.SysMenus
                                      where n.IsDeleted == false
                                      select n).ToListAsync().ConfigureAwait(false);

                var perList = list.ToList();
                foreach (var menu in perList)
                {
                    GetParents(menuList, list, menu);
                }

                #endregion 查找出权限对应的菜单的所有上级菜单，他们也应该加载处理

                list = list.OrderBy(p => p.RoleId).OrderBy(p => p.MenuId).OrderBy(p => p.MenuLevel).OrderBy(p => p.MenuSort).ToList();

                #endregion 查询数据库配置的权限

                cached.Set(keyStrHash, list, RedisHelper.GetCommonTimeSpan(), true);
                return list;
            }
        }

        /// <summary>
        /// 添加当前菜单的所有父级菜单到结果列表中
        /// </summary>
        /// <param name="menuList">所有的菜单集合</param>
        /// <param name="listResult">结果集合</param>
        /// <param name="roleMenuPermissionDto"></param>
        private void GetParents(List<SysMenu> menuList, List<RoleMenuPermissionDto> listResult, RoleMenuPermissionDto roleMenuPermissionDto)
        {
            var curMenu = menuList.Where(p => p.MenuId == roleMenuPermissionDto.MenuId).FirstOrDefault();
            if (curMenu.ParentId == Guid.Empty || curMenu.ParentId == null)
            {
                if (listResult.Count(p => p.MenuId == curMenu.MenuId) == 0)
                {
                    listResult.Add(new RoleMenuPermissionDto
                    {
                        RoleId = roleMenuPermissionDto.RoleId,
                        RoleName = roleMenuPermissionDto.RoleName,
                        FuncType = RoleMenuPermissionDto.FuncTypeEnum.菜单.ToString(),
                        RolePermissionId = Guid.Empty,

                        MenuId = curMenu.MenuId,
                        MenuName = curMenu.Name,
                        MenuComponent = curMenu.Component,
                        MenuIcon = curMenu.Icon,
                        MenuLevel = curMenu.Level,
                        MenuSort = curMenu.Sort,
                        MenuUrl = curMenu.Url,
                        ParentMenuId = curMenu.ParentId.ToGuid()
                    });
                }
            }
            else
            {
                var parentDto = new RoleMenuPermissionDto()
                {
                    RoleId = roleMenuPermissionDto.RoleId,
                    RoleName = roleMenuPermissionDto.RoleName,
                    MenuId = curMenu.ParentId.ToGuid()
                };

                GetParents(menuList, listResult, parentDto);
            }
        }
    }
}